package com.ytjj.qmyx.admin.service.imService.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.ytjj.common.constants.im.ImRedisKeyConstant;
import com.ytjj.common.exception.ApiException;
import com.ytjj.common.service.RedisService;
import com.ytjj.qmyx.admin.eunm.im.YxImServiceUserStatusEnum;
import com.ytjj.qmyx.admin.mapper.ImServiceUserMapper;
import com.ytjj.qmyx.admin.mapper.ImSessionInfoMapper;
import com.ytjj.qmyx.admin.model.ImServiceUser;
import com.ytjj.qmyx.admin.model.ImServiceUserExample;
import com.ytjj.qmyx.admin.model.ImSessionInfo;
import com.ytjj.qmyx.admin.model.dto.ImServiceUserDto;
import com.ytjj.qmyx.admin.model.dto.ImSessionInfoDto;
import com.ytjj.qmyx.admin.model.request.im.ImSessionTransferRequest;
import com.ytjj.qmyx.admin.model.response.im.ImServiceUserResponse;
import com.ytjj.qmyx.admin.model.vo.ImServiceUserVO;
import com.ytjj.qmyx.admin.service.imService.ImServiceUserService;
import com.ytjj.qmyx.admin.service.imService.ImSessionInfoService;
import com.ytjj.qmyx.admin.service.imService.ImSessionTransInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;


import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ImServiceUserServicempl implements ImServiceUserService {

    @Resource
    private ImServiceUserMapper imServiceUserMapper;
    @Resource
    private ImSessionInfoMapper imSessionInfoMapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ImSessionInfoService imSessionInfoService;
    @Autowired
    private ImSessionTransInfoService imSessionTransInfoService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 获取客服状态
     *
     * @return
     */
    @Override
    public ImServiceUserResponse getUserStatus(String userId) {
        List<ImServiceUserResponse> imServiceUsers = imServiceUserMapper.selectByUserId(userId);
        if (!CollectionUtils.isEmpty(imServiceUsers)) {
            redisService.set(ImRedisKeyConstant.IM_SERVICE_STATUS + userId, String.valueOf(imServiceUsers.get(0).getStatus()));
            List<ImServiceUserResponse> imServiceUserResponseList = imServiceUsers.stream().filter(item -> item.getRoleId().equals(2)).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(imServiceUserResponseList)) {
                return imServiceUserResponseList.get(0);
            }
            return imServiceUsers.get(0);
        }
        return null;
    }


    /**
     * 修改客服状态
     *
     * @param imServiceUserVO
     * @return
     */
    @Override
    public int updateUserStatus(ImServiceUserVO imServiceUserVO) {
        //客服可以离线的情况: 没有会话 或者 有其他客服在线
        if (YxImServiceUserStatusEnum.OFFLINE.getCode().byteValue() == imServiceUserVO.getStatus()) {
            judgeIsOffLine(imServiceUserVO);
        }
        //从redis中获取当前客服修改前的状态
        String oldStatus = redisService.get(ImRedisKeyConstant.IM_SERVICE_STATUS + imServiceUserVO.getUserId());

        //修改数据库状态
        int count = 0;
        List<ImServiceUser> imServiceUsers = getImServiceUsers(imServiceUserVO.getUserId());
        if (!CollectionUtils.isEmpty(imServiceUsers)){
            ImServiceUser OldImServiceUser = imServiceUsers.get(0);
            OldImServiceUser.setStatus(imServiceUserVO.getStatus());
            count = imServiceUserMapper.updateByPrimaryKey(OldImServiceUser);
        }
        if (count <= 0) {
            return count;
        }

        //作计时处理
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String curDate = sdf.format(new Date());

        //当原来状态为小休改为在线时--------------------------------------------------------------------------------
        if ("2".equals(oldStatus) && YxImServiceUserStatusEnum.ONLINE.getCode().byteValue() == imServiceUserVO.getStatus()) {
            //设置首次在线时间
            if (null == redisService.get(ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME + curDate + ":" + imServiceUserVO.getUserId())) {
                redisService.set(ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME + curDate + ":" + imServiceUserVO.getUserId(), String.valueOf(System.currentTimeMillis()));//设置客服在线时的时间
            }
            //客服每次设置在线的时间
            redisService.set(ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId(), String.valueOf(System.currentTimeMillis()));
            //计算小休时间 (当前时间减去上次设置成小休的时间)
            //上次设置成小休的时间
            String restTimeEveryTime = redisService.get(ImRedisKeyConstant.IM_REST_SERVICE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId());
            if (null != restTimeEveryTime) {
                Long restTime = System.currentTimeMillis() - Long.valueOf(restTimeEveryTime);
                //设置每日小休时长
                redisService.increment(ImRedisKeyConstant.IM_REST_TIME + curDate + ":" + imServiceUserVO.getUserId(), restTime);
            }
            //设置客服状态
            redisService.set(ImRedisKeyConstant.IM_SERVICE_STATUS + imServiceUserVO.getUserId(), YxImServiceUserStatusEnum.ONLINE.getCode().toString());
            //当原来状态为离线改为在线时--------------------------------------------------------------------------------
        } else if ("3".equals(oldStatus) && YxImServiceUserStatusEnum.ONLINE.getCode().byteValue() == imServiceUserVO.getStatus()) {
            //设置首次在线时间
            if (null == redisService.get(ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME + curDate + ":" + imServiceUserVO.getUserId())) {
                redisService.set(ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME + curDate + ":" + imServiceUserVO.getUserId(), String.valueOf(System.currentTimeMillis()));//设置客服在线时的时间
            }
            //客服每次设置在线的时间
            redisService.set(ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId(), String.valueOf(System.currentTimeMillis()));
            //计算离线时间 (当前时间减去上次设置成离线的时间)
            //上次设置成离线的时间
            String offlineTimeEveryTime = redisService.get(ImRedisKeyConstant.IM_SERVICE_UNLINE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId());
            if (null != offlineTimeEveryTime) {
                Long offlineTime = System.currentTimeMillis() - Long.valueOf(offlineTimeEveryTime);
                //增加每日离线时长
                redisService.increment(ImRedisKeyConstant.IM_SERVICE_OFFLINE_TIME + curDate + ":" + imServiceUserVO.getUserId(), offlineTime);
            }
            //设置客服状态
            redisService.set(ImRedisKeyConstant.IM_SERVICE_STATUS + imServiceUserVO.getUserId(), YxImServiceUserStatusEnum.ONLINE.getCode().toString());

            //客服上线 先接排队的人
            try {
                Map<String,String> map = Maps.newHashMap();
                map.put("type","join");
                stringRedisTemplate.convertAndSend("channel:imCluster", JSON.toJSONString(map));
            } catch (Exception e) {

            }

            // 当原来状态为在线改为小休时--------------------------------------------------------------------------------
        } else if ("1".equals(oldStatus) && YxImServiceUserStatusEnum.REST.getCode().byteValue() == imServiceUserVO.getStatus()) {
            //客服每次设置小休的时间
            redisService.set(ImRedisKeyConstant.IM_REST_SERVICE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId(), String.valueOf(System.currentTimeMillis()));
            //上次设置成在线的时间
            String onlineTimeEveryTime = redisService.get(ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId());
            if (null != onlineTimeEveryTime) {
                Long offlineTime = System.currentTimeMillis() - Long.valueOf(onlineTimeEveryTime);
                //增加每日在线时长
                redisService.increment(ImRedisKeyConstant.IM_SERVICE_TIME + curDate + ":" + imServiceUserVO.getUserId(), offlineTime);
            }
            //增加每日小休次数
            redisService.increment(ImRedisKeyConstant.IM_SERVICE_REST_NUM + curDate + ":" + imServiceUserVO.getUserId(), 1);
            //设置客服状态
            redisService.set(ImRedisKeyConstant.IM_SERVICE_STATUS + imServiceUserVO.getUserId(), YxImServiceUserStatusEnum.REST.getCode().toString());
            //当原来状态为离线改为小休时--------------------------------------------------------------------------------
        } else if ("3".equals(oldStatus) && YxImServiceUserStatusEnum.REST.getCode().byteValue() == imServiceUserVO.getStatus()) {
            //客服每次设置小休的时间
            redisService.set(ImRedisKeyConstant.IM_REST_SERVICE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId(), String.valueOf(System.currentTimeMillis()));
            //上次设置成离线的时间
            String offlineTimeEveryTime = redisService.get(ImRedisKeyConstant.IM_SERVICE_UNLINE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId());
            if (null != offlineTimeEveryTime) {
                Long offlineTime = System.currentTimeMillis() - Long.valueOf(offlineTimeEveryTime);
                //增加每日离线时长
                redisService.increment(ImRedisKeyConstant.IM_SERVICE_OFFLINE_TIME + curDate + ":" + imServiceUserVO.getUserId(), offlineTime);
            }
            //增加每日小休次数
            redisService.increment(ImRedisKeyConstant.IM_SERVICE_REST_NUM + curDate + ":" + imServiceUserVO.getUserId(), 1);
            //设置客服状态
            redisService.set(ImRedisKeyConstant.IM_SERVICE_STATUS + imServiceUserVO.getUserId(), YxImServiceUserStatusEnum.REST.getCode().toString());
            //当原来状态为在线改为离线时    --------------------------------------------------------------------------------
        } else if ("1".equals(oldStatus) && YxImServiceUserStatusEnum.OFFLINE.getCode().byteValue() == imServiceUserVO.getStatus()) {
            //客服每次设置离线的时间
            redisService.set(ImRedisKeyConstant.IM_SERVICE_UNLINE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId(), String.valueOf(System.currentTimeMillis()));
            //上次设置成在线的时间
            String onlineTimeEveryTime = redisService.get(ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId());
            if (null != onlineTimeEveryTime) {
                Long onlineTime = System.currentTimeMillis() - Long.valueOf(onlineTimeEveryTime);
                //增加每日在线时长
                redisService.increment(ImRedisKeyConstant.IM_SERVICE_TIME + curDate + ":" + imServiceUserVO.getUserId(), onlineTime);
            }
            // 查出客服下所有的在线会话  清除客户的绑定关系im系统那边要用到
            doOffLine(imServiceUserVO, curDate);
            //当原来状态为小休改为离线时  --------------------------------------------------------------------------------
        } else if ("2".equals(oldStatus) && YxImServiceUserStatusEnum.OFFLINE.getCode().byteValue() == imServiceUserVO.getStatus()) {
            //客服每次设置离线的时间
            redisService.set(ImRedisKeyConstant.IM_SERVICE_UNLINE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId(), String.valueOf(System.currentTimeMillis()));
            //上次设置成小休的时间
            String restTimeEveryTime = redisService.get(ImRedisKeyConstant.IM_REST_SERVICE_TIME_EVERY_TIME + curDate + ":" + imServiceUserVO.getUserId());
            if (null != restTimeEveryTime) {
                Long restTime = System.currentTimeMillis() - Long.valueOf(restTimeEveryTime);
                //增加每日小休时长
                redisService.increment(ImRedisKeyConstant.IM_REST_TIME + curDate + ":" + imServiceUserVO.getUserId(), restTime);
            }
            // 查出客服下所有的在线会话  清除客户的绑定关系im系统那边要用到
            doOffLine(imServiceUserVO, curDate);
        }


//        //当状态在线改为小休时,记录客服在线时间
//        if (YxImServiceUserStatusEnum.REST.getCode().byteValue() == imServiceUserVO.getStatus()) {
//            doRest(imServiceUserVO.getUserId());
//            //设置客服状态
//            redisService.set(ImRedisKeyConstant.IM_SERVICE_STATUS + imServiceUserVO.getUserId(), YxImServiceUserStatusEnum.REST.getCode().toString());
//            //设置客服每日小休次数
//            redisService.increment(ImRedisKeyConstant.IM_SERVICE_REST_NUM + curDate + ":" + imServiceUserVO.getUserId(), 1);
//         //当客服小休改为在线时,记录小休时间
//        } else if (YxImServiceUserStatusEnum.ONLINE.getCode().byteValue() == imServiceUserVO.getStatus()) {
//            doOnline(imServiceUserVO.getUserId());
//            //设置客服状态
//            redisService.set(ImRedisKeyConstant.IM_SERVICE_STATUS + imServiceUserVO.getUserId(), YxImServiceUserStatusEnum.ONLINE.getCode().toString());
//        } else if (YxImServiceUserStatusEnum.OFFLINE.getCode().byteValue()==imServiceUserVO.getStatus()) {
//            String serviceStatusByRedis = redisService.get(ImRedisKeyConstant.IM_SERVICE_STATUS + imServiceUserVO.getUserId());
//            if (YxImServiceUserStatusEnum.REST.getCode().toString().equals(serviceStatusByRedis)) {
//                doRest(imServiceUserVO.getUserId());
//            } else if (YxImServiceUserStatusEnum.ONLINE.getCode().toString().equals(serviceStatusByRedis)) {
//                doOnline(imServiceUserVO.getUserId());
//            }
//            // 查出客服下所有的在线会话  清除客户的绑定关系im系统那边要用到
//            doOffLine(imServiceUserVO, curDate);
//        }
        return count;
    }

    private void judgeIsOffLine(ImServiceUserVO imServiceUserVO) {
        //查看该客服是否有会话
        List<ImSessionInfoDto> sessionList = imSessionInfoMapper.selectSessionByUserId(imServiceUserVO.getUserId());
        //当前该客服没有会话
        if (CollectionUtils.isEmpty(sessionList)){
            return;
        }
        Integer conNum = sessionList.size();//当前聊天中的数量

        //查询当前在线客服人数,去除该客服后剩下的在线客服
        List<ImServiceUserDto> serviceUserList = imServiceUserMapper.selectServiceByStatus().stream().filter(s -> !s.getUserId().equals(imServiceUserVO.getUserId())).collect(Collectors.toList());
        //当前该客服有会话但没有其他客服在线
        if (conNum > 0 && CollectionUtils.isEmpty(serviceUserList)) {
            throw new ApiException("当前有会话沟通中且没有其他客服在线,不能设置离线,请结束会话后再离线");
        }
        List<String> emailList = new ArrayList<>();
        serviceUserList.forEach(item ->{
            emailList.add(item.getUserId());
        });
        //todo 没有考虑客服的接待量,直接随机转移到在线客服中
        sessionList.forEach(item ->{
            //随机取一个客服
            Random random = new Random();
            int n = random.nextInt(emailList.size());
            String targetUserId = emailList.get(n);
            //把会话转移
            ImSessionTransferRequest imSessionTransferRequest = new ImSessionTransferRequest();
            imSessionTransferRequest.setSourceUserId(imServiceUserVO.getUserId());
            imSessionTransferRequest.setTargetUserId(targetUserId);
            imSessionTransferRequest.setSessionId(item.getId());
            imSessionTransferRequest.setRemak("离线转移");
            imSessionTransInfoService.doTrans(imSessionTransferRequest);
        });



//        //其他在线客服的总服务上限
//        Integer countMax = 0;
//        //其他客服目前的总沟通中的会话数量
//        Integer sessionNum = 0;
//        //查询其他客服
//        for (ImServiceUserDto userDto : serviceUserList) {
//            countMax = countMax + (null == userDto.getMaxConNum() ? 10 : userDto.getMaxConNum());
//            Short conNum1 = userDto.getConNum();
//            sessionNum = sessionNum + conNum1;
//            Integer maxConNum = userDto.getMaxConNum();
//            Double cardinalNum = Double.valueOf(conNum1 / maxConNum);
//            userDto.setCardinalNum(cardinalNum);//接待基数-------正在沟通中的数量除以服务上限数
//        }
//        //当前有会话沟通中且大于其他客服可转移数量
//        if (conNum > 0 && serviceUserList.size() > 0 && conNum > (countMax - sessionNum)) {
//            throw new ApiException("当前有会话沟通中且大于其他在线客服可转移数量,不能设置离线,请结束会话后再离线");
//        }
//        //把客服沟通中的会话转移到其他客服中
    }

    public void doOffLine(ImServiceUserVO imServiceUserVO, String curDate) {
        // 查出客服下所有的在线会话  清除客户的绑定关系im系统那边要用到
        List<ImSessionInfo> sessionInfos = imSessionInfoService.querySessionListByServiceId(imServiceUserVO.getUserId(), 1);
        if (!CollectionUtils.isEmpty(sessionInfos)) {
            sessionInfos.stream().forEach(item -> {
                redisService.remove(ImRedisKeyConstant.IM_MEDIUMS_CUSTOMER + item.getCustomerId());
                redisService.remove(ImRedisKeyConstant.CUSTOMER_BIND_SERVICE + item.getCustomerId());
            });
        }
        //设置客服状态
        redisService.set(ImRedisKeyConstant.IM_SERVICE_STATUS + imServiceUserVO.getUserId(), YxImServiceUserStatusEnum.OFFLINE.getCode().toString());
        //设置客服每日离开次数
        redisService.increment(ImRedisKeyConstant.IM_SERVICE_UNLINE_NUM + curDate + ":" + imServiceUserVO.getUserId(), 1);
    }

    /**
     * 查询客服信息
     *
     * @param userId
     * @return
     */
    private List<ImServiceUser> getImServiceUsers(String userId) {
        ImServiceUserExample example = new ImServiceUserExample();
        example.createCriteria().andUserIdEqualTo(userId);
        return imServiceUserMapper.selectByExample(example);
    }

    /**
     * 小休处理
     * 1.缓存客服小休的开始时间
     * 2.计算在线时长，并且缓存起来
     *
     * @param userId
     */
    private void doRest(String userId) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String curDate = sdf.format(new Date());
        String unlineServiceTimeKey = ImRedisKeyConstant.IM_REST_SERVICE_TIME + curDate + ":" + userId;//客服小休redisKey
        redisService.set(unlineServiceTimeKey, String.valueOf(System.currentTimeMillis()));//设置客服小休时的时间
        redisService.expire(unlineServiceTimeKey, 18 * 60 * 60);
        //计时在线时长 客户从在线状态切换到小休才计算
        String serviceStatusByRedis = redisService.get(ImRedisKeyConstant.IM_SERVICE_STATUS + userId);
        if (YxImServiceUserStatusEnum.ONLINE.getCode().toString().equals(serviceStatusByRedis)) {
            //客服在线redisKey
            String onlineServieTimeKey = ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME + curDate + ":" + userId;//客服在线redisKey
            String loginTimeStr = redisService.get(onlineServieTimeKey);//登录时的时间
            redisService.delete(onlineServieTimeKey);//获取到数据后就清理掉
            if (StringUtils.isEmpty(loginTimeStr)) {
                loginTimeStr = "0";
            }

            Long loginTime = Long.parseLong(loginTimeStr);
            Long curTime = System.currentTimeMillis();
            Long onLineTime = (curTime - loginTime) / 1000;//在线时长（单位：秒）
            redisService.increment(ImRedisKeyConstant.IM_SERVICE_TIME + curDate + ":" + userId, onLineTime);
        } else if (YxImServiceUserStatusEnum.OFFLINE.getCode().toString().equals(serviceStatusByRedis)) {
            //从离线切换过来的
            log.info("===客服从离线状态切换到在线状态===");
        }
    }

    /**
     * 在线处理
     * 1.缓存客服在线的开始时间
     * 2.计算小休时长，并且缓存起来
     *
     * @param userId
     */
    private void doOnline(String userId) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String curDate = sdf.format(new Date());

        String onlineServieTimeKey = ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME + curDate + ":" + userId;//客服首次在线redisKey
        redisService.set(onlineServieTimeKey, String.valueOf(System.currentTimeMillis()));//设置客服在线时的时间
        //客服每次设置在线的时间
        redisService.set(ImRedisKeyConstant.IM_ONLINE_SERVICE_TIME_EVERY_TIME + curDate + ":" + userId, String.valueOf(System.currentTimeMillis()));
        redisService.expire(onlineServieTimeKey, 18 * 60 * 60);
        //计算小休时长 如果是从小休切换到在线才进行这部计算
        String serviceStatusByRedis = redisService.get(ImRedisKeyConstant.IM_SERVICE_STATUS + userId);
        if (YxImServiceUserStatusEnum.REST.getCode().toString().equals(serviceStatusByRedis)) {
            String unlineServiceTimeKey = ImRedisKeyConstant.IM_REST_SERVICE_TIME + curDate + ":" + userId;//客服小休redisKey
            String restTimeStr = redisService.get(unlineServiceTimeKey);//获取到小休开始时间
            redisService.delete(unlineServiceTimeKey);
            if (StringUtils.isEmpty(restTimeStr)) {
                restTimeStr = "0";
            }

            Long restStartTime = Long.parseLong(restTimeStr);
            Long curTime = System.currentTimeMillis();
            Long restTime = (curTime - restStartTime) / 1000;//小休时长（单位：秒）
            redisService.increment(ImRedisKeyConstant.IM_REST_TIME + curDate + ":" + userId, restTime);
        } else if (YxImServiceUserStatusEnum.OFFLINE.getCode().toString().equals(serviceStatusByRedis)) {
            //从离线状态切换过来
            log.info("===客服从离线状态切换到在线状态===");
        }
    }

    @Override
    public boolean insertOrUpdate(String email) {
        ImServiceUserExample example = new ImServiceUserExample();
        example.createCriteria().andUserIdEqualTo(email);
        List<ImServiceUser> users = imServiceUserMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(users)) {
            return insert(email);
        }

//        ImServiceUserVO imServiceUserVO = new ImServiceUserVO();
//        imServiceUserVO.setUserId(email);
//        imServiceUserVO.setStatus(YxImServiceUserStatusEnum.ONLINE.getCode().byteValue());
//        updateUserStatus(imServiceUserVO);
        return false;
    }


    public boolean insert(String userId) {
        ImServiceUser imServiceUser = new ImServiceUser();
        imServiceUser.setUserId(userId);
        imServiceUser.setStatus(YxImServiceUserStatusEnum.OFFLINE.getCode().byteValue());
        imServiceUser.setConNum((short) 1);
        doOnline(userId);
        return imServiceUserMapper.insertSelective(imServiceUser) > 0 ? true : false;
    }
}
